package fm.yichenet.mongo.service.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import fm.cache.AreaCache;
import fm.dao.HibernateBaseDao;
import fm.dao.MongoBaseDao;
import fm.dto.NeiyiUser;
import fm.entityEnum.CollectTypeEnum;
import fm.entityEnum.ShopFlagEnum;
import fm.exception.BizException;
import fm.mongo.MCondition;
import fm.mongo.MRel;
import fm.mongo.MongoTable;
import fm.mongoService.UserService;
import fm.nio.SemaphoreExecutor;
import fm.util.CommonUtils;
import fm.web.CurrentRequest;
import fm.yichenet.mongo.service.ShopMgrService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Query;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * @修改人：CM
 * @修改时间：2017/3/15 13:20
 */
@Service
public class ShopMgrServiceImpl implements ShopMgrService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ShopMgrService.class);
    @Autowired
    MongoBaseDao baseDao;
    @Autowired
    HibernateBaseDao hibernateBaseDao;
    @Autowired
    UserService userService;

    @Override
    public List<DBObject> getContactInfoByPage(Integer pageNum, Integer pageSize) throws Exception {
        Map param = new HashMap();
        return (List<DBObject>) baseDao.getPageList(param, DBObject.class, pageSize, pageNum, MongoTable.contact);
    }

    @Override
    public void updateMapConfig(Map mapConfig) throws Exception {
        DBObject query = new BasicDBObject("uuid", mapConfig.get("uuid"));
        Object queryOne = baseDao.findOne(query.toMap(), DBObject.class, MongoTable.aboutConfig);
        if (queryOne != null) {
            baseDao.updateOne(query.toMap(), mapConfig, MongoTable.aboutConfig);
        } else {
            baseDao.insert(mapConfig, MongoTable.aboutConfig);
        }
    }

    @Override
    public void updateAboutContent(Map content) throws Exception {
        DBObject query = new BasicDBObject("uuid", content.get("uuid"));
        Object queryOne = baseDao.findOne(query.toMap(), DBObject.class, MongoTable.aboutConfig);
        if (queryOne != null) {
            baseDao.updateOne(query.toMap(), content, MongoTable.aboutConfig);
        } else {
            baseDao.insert(content, MongoTable.aboutConfig);
        }

    }

    @Override
    public DBObject getAboutConfig(Map param) throws Exception {
        return (DBObject) baseDao.findOne(param, DBObject.class, MongoTable.aboutConfig);
    }

    @Override
    public DBObject getHomeConfig(Map param) throws Exception {
        DBObject queryOne = (DBObject) baseDao.findOne(param, DBObject.class, MongoTable.homeConfig);
        return queryOne;
    }

    @Override
    public void updateHomeConfig(Map config) throws Exception {
        DBObject query = new BasicDBObject("uuid", config.get("uuid"));
        Object queryOne = baseDao.findOne(query.toMap(), DBObject.class, MongoTable.homeConfig);
        if (queryOne != null) {
            baseDao.updateOne(query.toMap(), config, MongoTable.aboutConfig);
        } else {
            baseDao.insert(config, MongoTable.aboutConfig);
        }
    }

    @Override
    public DBObject getGoodClassByUuid(Map param) throws Exception {
        return (DBObject) baseDao.findOne(param, DBObject.class, MongoTable.goodClass);
    }

    @Override
    public void addGoodClass(Map data) throws Exception {
        baseDao.insert(data, MongoTable.goodClass);
    }

    @Override
    public void updateGoodClass(Map data) {
        Map query = new HashMap();
        query.put("uuid", data.get("uuid"));
        baseDao.updateOne(query, data, MongoTable.goodClass);
    }

    @Override
    public void flagShop(String shopId, String action, String city, ShopFlagEnum pageType) throws Exception {
        MCondition mc = MCondition.create(MRel.and);
        mc.append("_id", shopId);
        DBObject existsShop = (DBObject) baseDao.findOne(mc.toDBObject().toMap(), DBObject.class, MongoTable.user);
        List<Map<String, String>> flags = (List<Map<String, String>>) existsShop.get("flags");
        Map param = new HashMap();


        if ("ADD".equals(action)) {
            //

            boolean existsFlag = false;
            if (flags == null) {
                flags = new ArrayList<>();
            } else {
                param.put("flags.name", pageType.toString());
                long count = baseDao.count(param, MongoTable.user);
                if (count - pageType.getNum() >= 0) {
                    throw new BizException(pageType.getDesc() + "模块最多只能配置" + pageType.getNum() + "个商品!");
                }
                for (Map<String, String> flag : flags) {
                    if (flag.get("name").equals(pageType.toString()) && flag.get("city").equals(city)) {
                        existsFlag = true;
                        break;
                    }
                }
            }
            if (!existsFlag) {
                Map<String, String> newFlag = new HashMap<>();
                newFlag.put("name", pageType.toString());
                newFlag.put("city", city);
                if ("default".equals(city)) {
                    newFlag.put("city_desc", "默认全国");
                } else {
                    newFlag.put("city_desc", AreaCache.getAddress(city).getName());
                }
                flags.add(newFlag);
                existsShop.put("flags", flags);
                baseDao.updateOne(mc.toDBObject().toMap(), existsShop.toMap(), MongoTable.user);
            }

        } else if ("DELETE".equals(action)) {
            List<Map<String, String>> newflags = new ArrayList<>();
            if (flags.size() > 1) {
                for (Map<String, String> flag : flags) {
                    if (flag.get("name").equals(pageType.toString()) && flag.get("city").equals(city)) {

                        continue;
                    } else {
                        newflags.add(flag);
                    }
                }
            }
            existsShop.put("flags", newflags);
            baseDao.updateOne(mc.toDBObject().toMap(), existsShop.toMap(), MongoTable.user);
        }
    }

    @Override
    public List<DBObject> getFlagShop(String pagetype, String city) throws Exception {
        List<DBObject> shopIds = null;
        MCondition mc = MCondition.create(MRel.and);
        mc.append("flags.name", pagetype);
        if (StringUtils.isNotEmpty(city)) {
            mc.append("flags.city", city);
        }
        shopIds = (List<DBObject>) baseDao.getList(mc.toDBObject().toMap(), DBObject.class, MongoTable.user);
        return shopIds;
    }

    @Override
    public List getShopList(String shopType, String keyword, Double longitude, Double latitude, String province, String city, Integer pageSize, Integer pageNum) throws Exception {
        Integer start;
        Integer end;

        if (pageNum == 0) {
            pageNum = 1;
        }

        start = (pageNum - 1) * pageSize;

        List<Map> list;
        String sql = getShopQueryString(latitude, longitude, keyword, province, city, shopType);
        sql += " limit " + start + "," + pageSize;


        LOGGER.info("店铺查询条件:{}", sql);
        Query query = hibernateBaseDao.getHibernateTemplate().getSessionFactory().getCurrentSession().createSQLQuery(sql);
        query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        list = query.list();
        final List<Map<String, Object>> resList = new ArrayList<>();

//        if (CollectionUtils.isNotEmpty(list)) {
//
//            //多线程异步需要同步机制
//            final CountDownLatch cdl = new CountDownLatch(list.size());
//            SemaphoreExecutor executor = new SemaphoreExecutor(10, "queryMerchantThreads");
//            for (final Map objects : list) {
//                executor.execute(new Runnable() {
//                    @Override
//                    public void run() {
//                        try {
//
//                            Long id = Long.parseLong(String.valueOf(objects[0]));
//                            Map<String, Object> query = new HashedMap();
//                            query.put("id", id);
//                            DBObject merchant = (DBObject) baseDao.findOne(query, DBObject.class, MongoTable.merchant_auth_info);
//
//                            Map<String, Object> map = new HashedMap();
//
//                            map.put("id", id);
//                            map.put("distance", CommonUtils.isEmpty(objects[1]) ? "" : objects[1]);
//                            map.put("headimgurl", CommonUtils.isEmpty(objects[2]) ? "" : objects[2]);
//                            map.put("portal_img", CommonUtils.isEmpty(objects[3]) ? "" : objects[3]);
//                            if (!CommonUtils.isEmpty(merchant)) {
//                                map.put("company_name", CommonUtils.isEmpty(merchant.get("company_name")) ? null : merchant.get("company_name"));
//                                map.put("address", CommonUtils.isEmpty(merchant.get("address")) ? null : merchant.get("address"));
//                                map.put("charge_person_name", CommonUtils.isEmpty(merchant.get("charge_person_name")) ? "" : merchant.get("charge_person_name"));
//                                map.put("telephone", CommonUtils.isEmpty(merchant.get("telephone")) ? null : merchant.get("telephone"));
//                                map.put("pics", CommonUtils.isEmpty(merchant.get("pics")) ? null : merchant.get("pics"));
//                                map.put("desc", CommonUtils.isEmpty(merchant.get("desc")) ? null : merchant.get("desc"));
//                                map.put("province", CommonUtils.isEmpty(merchant.get("province")) ? null : merchant.get("province"));
//                                map.put("city", CommonUtils.isEmpty(merchant.get("city")) ? null : merchant.get("city"));
//                                map.put("district", CommonUtils.isEmpty(merchant.get("district")) ? null : merchant.get("district"));
//                                map.put("street", CommonUtils.isEmpty(merchant.get("street")) ? null : merchant.get("street"));
//                                map.put("street_number", CommonUtils.isEmpty(merchant.get("street_number")) ? null : merchant.get("street_number"));
//                                Map<String, Object> queryCount = new HashedMap();
//                                queryCount.put("wx_user_id", id);
//                                Long good_count = baseDao.count(queryCount, MongoTable.good);
//                                map.put("good_count", good_count);
//                            }
//                            resList.add(map);
//                        } catch (Exception ex) {
//                            LOGGER.error("获取商铺列表认证资料发生错误:", ex);
//                        } finally {
//                            //多线程执行结果等待计数器，-1
//                            cdl.countDown();
//                        }
//                    }
//                });
//            }
//
//            //等待线程同步结束后再继续后面的代码片段
//            cdl.await();
//        }
        return list;
    }

    @Override
    public void collectShop(String shopId, NeiyiUser user) throws Exception {
        Map<String, Object> query = new HashedMap();
        query.put("user_id", user.getId());
        query.put("shop_id", shopId);
        DBObject shopCollection = (DBObject) baseDao.findOne(query, DBObject.class, MongoTable.shop_collection);
        if (!CommonUtils.isEmpty(shopCollection)) {
            throw new BizException("该店铺已被收藏");
        } else {
            Timestamp now = new Timestamp(System.currentTimeMillis());
            query.put("collection_time", now);
            baseDao.insert(query, MongoTable.shop_collection);
        }
    }

    @Override
    public Map<String, Object> checkCollectShop(String shopId, NeiyiUser user) throws Exception {
        Map<String, Object> query = new HashedMap();
        Map<String, Object> res = new HashedMap();
        query.put("user_id", user.getId());
        query.put("shop_id", shopId);
        DBObject shopCollection = (DBObject) baseDao.findOne(query, DBObject.class, MongoTable.shop_collection);
        if (!CommonUtils.isEmpty(shopCollection)) {
            res.put("checkState", "isCollect");
//            return res;
        } else {
            res.put("checkState", "notCollect");
        }
        return res;
    }

    @Override
    public void unCollectShop(String shopId, NeiyiUser user) throws Exception {
        Map<String, Object> query = new HashedMap();
        query.put("user_id", user.getId());
        query.put("shop_id", shopId);
        baseDao.delete(query, MongoTable.shop_collection);
    }

    @Override
    public List getCollectionShopList(NeiyiUser user, Integer pageSize, Integer pageNum) throws Exception {
        Map<String, Object> query = new HashedMap();
        query.put("user_id", user.getId());
        DBObject sort = new BasicDBObject("collection_time", Sort.Direction.DESC.toString());
        List<DBObject> list = (List<DBObject>) baseDao.getPageList(query, DBObject.class, pageSize, pageNum, MongoTable.shop_collection, sort);
        final List<Map<String, Object>> resList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(list)) {

            //多线程异步需要同步机制
            final CountDownLatch cdl = new CountDownLatch(list.size());
            SemaphoreExecutor executor = new SemaphoreExecutor(10, "queryCollectionShopThreads");

            for (final DBObject dbObject : list) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {

//                            Long id = Long.parseLong(String.valueOf(dbObject.get("shop_id")));
                            String id = String.valueOf(dbObject.get("shop_id"));
                            Map<String, Object> query = new HashedMap();
//                            query.put("_id", id);
//                            NeiyiUser user = (NeiyiUser) baseDao.findOne(query, DBObject.class, MongoTable.user);
                            NeiyiUser user = userService.getById(id);
//                            NeiyiUser user = (NeiyiUser) hibernateBaseDao.getById(NeiyiUser.class, id);
                            Map<String, Object> map = new HashedMap();
                            map.put("id", id);
                            map.put("userLogo", CommonUtils.isEmpty(user.getUserLogo()) ? "" : user.getUserLogo());
                            if (!CommonUtils.isEmpty(user)) {
                                map.put("company_name", CommonUtils.isEmpty(user.getCompanyName()) ? "" : user.getCompanyName());
//                                map.put("address", CommonUtils.isEmpty(user.get("address")) ? "" : user.get("address"));
//                                map.put("charge_person_name", CommonUtils.isEmpty(merchant.get("charge_person_name")) ? "" : merchant.get("charge_person_name"));
//                                map.put("telephone", CommonUtils.isEmpty(merchant.get("telephone")) ? "" : merchant.get("telephone"));
                                map.put("pics", CommonUtils.isEmpty(user.getCompanyPics()) ? "" : user.getCompanyPics());
                                map.put("desc", CommonUtils.isEmpty(user.getUserDsc()) ? "" : user.getUserDsc());
//                                map.put("province", CommonUtils.isEmpty(user.get("province")) ? "" : user.get("province"));
//                                map.put("city", CommonUtils.isEmpty(user.get("city")) ? "" : user.get("city"));
//                                map.put("district", CommonUtils.isEmpty(user.get("district")) ? "" : user.get("district"));
//                                map.put("street", CommonUtils.isEmpty(user.get("street")) ? "" : user.get("street"));
//                                map.put("street_number", CommonUtils.isEmpty(user.get("street_number")) ? "" : user.get("street_number"));
                                Map<String, Object> queryCount = new HashedMap();
                                queryCount.put("user_id", id);
                                Long good_count = baseDao.count(queryCount, MongoTable.good);
                                map.put("good_count", good_count);
                            }
                            resList.add(map);
                        } catch (Exception ex) {
                            LOGGER.error("获取收藏店铺列表发生错误:", ex);
                        } finally {
                            //多线程执行结果等待计数器，-1
                            cdl.countDown();
                        }
                    }
                });
            }

            //等待线程同步结束后再继续后面的代码片段
            cdl.await();
        }
        return resList;
    }

    /**
     * 商铺代理品牌管理
     *
     * @param action
     * @param brandName
     * @param brandLogo
     * @param shopId
     * @throws Exception
     */
    @Override
    public void agencyBrandMg(String action, String brandName, String brandLogo, String shopId) throws Exception {
        if (!CurrentRequest.isAdmin()) {
            shopId = CurrentRequest.getCurrentUserId().toString();
        }
        NeiyiUser user = userService.getById(shopId);
        if (user == null) {
            throw new BizException("未找到对应商户信息，配置失败！");
        }
        List<Map<String, String>> brandlist = user.getAgencyBrandList();
        if ("ADD".equals(action)) {
            if (CommonUtils.isEmpty(brandName)) {
                throw new BizException("请输入品牌名称!");
            }
            if (CommonUtils.isEmpty(brandLogo)) {
                throw new BizException("请上传品牌logo!");
            }

            boolean existsFlag = false;
            if (brandlist == null) {
                brandlist = new ArrayList<>();
            } else {
                for (Map<String, String> flag : brandlist) {
                    if (flag.get("name").equals(brandName)) {
                        existsFlag = true;
                        break;
                    }
                }
            }
            if (!existsFlag) {
                Map<String, String> newbrand = new HashMap<>();
                newbrand.put("name", brandName);
                newbrand.put("img", brandLogo);
                brandlist.add(newbrand);
                Map query = new HashMap();
                query.put("_id", shopId);
                Map updateItem = new HashMap();
                updateItem.put("agencyBrandList", brandlist);
                userService.updateUserInfo(query, updateItem);
            }
        } else if ("DELETE".equals(action)) {
            List<Map<String, String>> newbrandlist = new ArrayList<>();
            if (brandlist.size() > 1) {
                for (Map<String, String> brand : brandlist) {
                    if (brand.get("name").equals(brandName)) {

                        continue;
                    } else {
                        newbrandlist.add(brand);
                    }
                }
            }
            Map query = new HashMap();
            query.put("_id", shopId);
            Map updateItem = new HashMap();
            updateItem.put("agencyBrandList", newbrandlist);
            userService.updateUserInfo(query, updateItem);
        }
    }

    @Override
    public List getAgencyBrandList(String shopId) {
        NeiyiUser user = (NeiyiUser) userService.getById(shopId);
        if (user == null) {
            throw new BizException("用户不存在!");
        }
        List brandList = user.getAgencyBrandList();
        return brandList;
    }

    /**
     * 获取物流报价信息
     *
     * @param list
     * @param user_id
     */
    @Override
    public void getLogPriceInfoByExcel(List<Map<String, Object>> list, String user_id) {
        if (list.isEmpty()) {
            throw new BizException("文件为空请重新上传!");
        }
        NeiyiUser user = userService.getById(user_id);

        if (user == null) {
            throw new BizException("当前用户不存在!");
        }

        List<Map<String, String>> logPriceList = new ArrayList<>();
        Map queryparam = new HashMap();
        queryparam.put("id", user_id);

        for (Map<String, Object> item : list.subList(1, list.size())) {
            Map logPrice = new HashMap();

            if (CommonUtils.isEmpty(item)) {
                continue;
            }
            logPrice.put("area", item.get("value1"));
            logPrice.put("firstPrice", item.get("value2"));
            logPrice.put("nextPrice", item.get("value3"));
            logPriceList.add(logPrice);
        }

        Map updateItem = new HashMap();
        updateItem.put("logPriceList", logPriceList);

        userService.updateUserInfo(queryparam, updateItem);

    }

    @Override
    public List getCollectList(String user_id, CollectTypeEnum type) throws Exception {
        Map param = new HashMap();
        if (StringUtils.isNotEmpty(user_id)) {
            param.put("user_id", user_id);
        }
        if (CommonUtils.isEmpty(type)) {
            param.put("type", type);
        }
        List<DBObject> collectList = (List<DBObject>) baseDao.getList(param, DBObject.class, MongoTable.collection);
        return collectList;
    }

    @Override
    public void deleCollect(String id) throws Exception {
        Map param = new HashMap();
        param.put("id", id);
        baseDao.delete(param, MongoTable.collection);
    }

    @Override
    public void shopCollect(String shop_id, boolean flag) throws Exception {
        NeiyiUser user = userService.getById(shop_id);
        if (user == null) {
            throw new BizException("要收藏的店铺不存在!");
        }
        Map param = new HashMap();
        param.put("user_id", CurrentRequest.getCurrentUserId().toString());
        param.put("type", CollectTypeEnum.SHOP);
        param.put("id", shop_id);
        param.put("head_img", user.getUserLogo());
        param.put("name", user.getCompanyName());


        DBObject collect = (DBObject) baseDao.findOne(param, DBObject.class, MongoTable.collection);
        Map query = new HashMap();
        query.put("user_id", shop_id);
        Map update = new HashMap();

        if (collect == null && flag) {
            baseDao.insert(param, MongoTable.collection);
            user.setCollect_count(user.getCollect_count() == null ? 1 : user.getCollect_count() + 1);
            update.put("collect_count", user.getCollect_count());
            userService.updateUserInfo(query, update);
        } else if (collect != null && !flag) {
            baseDao.delete(param, MongoTable.collection);
            user.setCollect_count(user.getCollect_count() == null ? 0 : user.getCollect_count() - 1);
            update.put("collect_count", user.getCollect_count());
            userService.updateUserInfo(query, update);
        }
    }


    private String getShopQueryString(Double lat, Double lon, String keyword, String province, String city, String shopType) {
        if (lat == null) {
            lat = 0d;
        }
        if (lon == null) {
            lon = 0d;
        }
        double realLat = Math.min(lat, lon);
        double realLng = Math.max(lat, lon);

        DecimalFormat lonDf = new DecimalFormat("#.000000");
        DecimalFormat latDf = new DecimalFormat("#.00000");

        StringBuffer sb = new StringBuffer();
        sb.append("select * from (");

        //经纬度查询条件
        sb.append("select u.*,6378.138 * 2 * ASIN(SQRT(POW(SIN((").append(latDf.format(realLat)).append(" * PI() / 180 - u.latitude * PI() / 180) / 2),2)");
        sb.append("+ COS( ").append(latDf.format(realLat)).append(" * PI() / 180) * COS(u.latitude * PI() / 180) * POW(SIN((").append(lonDf.format(realLng)).append(" * PI() / 180 ");
        sb.append("- u.longitude * PI() / 180 ) / 2 ),2))) AS distance ");
        sb.append("from wx_user as u where (u.user_type = 3 or u.user_type = 4) and review_status = 2 and u.latitude is not null and u.longitude is not null");

        if (StringUtils.isNotEmpty(keyword)) {
            sb.append(" and u.nickname like '%").append(keyword).append("%' ");
        }

        if (StringUtils.isNotEmpty(province)) {
            sb.append(" and u.province='").append(province).append("' ");
        }

        if (StringUtils.isNotEmpty(city)) {
            sb.append(" and u.city='").append(city).append("' ");
        }

        if (StringUtils.isNotEmpty(shopType)) {
            sb.append(" and u.review_notes='").append(shopType).append("' ");

        }
        //无经纬度店铺的展示
        sb.append(" union  (select u1.*,999999 as distance  from wx_user u1 ")
                .append(" where  (u1.user_type = 3 or u1.user_type = 4) ")
                .append(" and u1.review_status = 2 and u1.longitude is null and u1.latitude is null");

        if (StringUtils.isNotEmpty(keyword)) {
            sb.append(" and u1.nickname like '%").append(keyword).append("%' ");
        }

        if (StringUtils.isNotEmpty(province)) {
            sb.append(" and u1.province='").append(province).append("' ");
        }

        if (StringUtils.isNotEmpty(city)) {
            sb.append(" and u1.city='").append(city).append("' ");
        }

        if (StringUtils.isNotEmpty(shopType)) {
            sb.append(" and u1.review_notes='").append(shopType).append("' ");

        }

        sb.append(")) a order by a.distance asc");


        return sb.toString();

    }
}
